<?php
$cal_cfg = array();
$cal_cfg['path'] = str_replace('\\', '/', dirname(__FILE__));
include($cal_cfg['path'] . '/config.php');

class WingedCalendar {
	var $templates;
	var $months;
	var $sunday_endweek;
	var $datapath;
	var $htpath;
	var $password;
	var $timezone;
	
	function WingedCalendar() {
		global $cal_cfg;
		$this->templates = $cal_cfg['template'];
		$this->password = $cal_cfg['password'];
		$this->sunday_endweek = $cal_cfg['sunday_endweek'];
		$this->months = $cal_cfg['month'];
		$this->timezone = $cal_cfg['timezone'];
		$this->datapath = $cal_cfg['path'] . '/data.txt';
		$this->htpath = str_replace($cal_cfg['document_root'], '', $cal_cfg['path']);
	}
	
	function getDate($time=0) {
		return $time==0? getdate(time() + $this->timezone*3600-intval(date('Z'))) : getdate($time + $this->timezone*3600-intval(date('Z')));
	}
	
	function getNumberOfDays($month, $year) {
		$numday = 31;
		if ($month==4 || $month==6 || $month==9 || $month==11) {
			$numday = 30;
		} else if ($month==2) {
			$numday = $year%4!=0 || ($year%100==0 && $year%400!=0)? $numday = 28 : 29;
		}
		return $numday;
	}

	function getMonthDetails($month, $year) {
		$details = array();
		$details['mon'] = $month;
		$details['year'] = $year;
		$details['days'] = $this->getNumberOfDays($month, $year);
		$details['month'] = $this->months[$month-1];
		$tmp = $this->getDate(gmmktime(0, 0, 0, $month, 1, $year));
		$details['first'] = $tmp['wday'];
		$details['last']['mon'] = $month-1;
		$details['last']['year'] = $year;
		$details['next']['mon'] = $month+1;
		$details['next']['year'] = $year;
		if ($month==1) {
			$details['last']['mon'] = 12;
			$details['last']['year']--;
		} else if ($month==12) {
			$details['next']['mon'] = 1;
			$details['next']['year']++;
		}
		$details['last']['days'] = $this->getNumberOfDays($details['last']['mon'], $details['last']['year']);
		return $details;
	}

	function getEvent($id) {
		$events = array();
		$lines = file($this->datapath);
		for ($i=0, $n=count($lines); $i<$n; $i++) {
			if (trim($lines[$i])=='<event>') {
				if (trim($lines[++$i])==$id) {
					$events['id'] = $id;
					list($events['day'], $events['month'], $events['year']) = explode('-', trim($lines[$i+1]));
					list($events['hr'], $events['min']) = explode(':', trim($lines[$i+2]));
					$events['message'] = '';
					for ($i+=3;; $i++) {
						if (trim($lines[$i])=='</event>') break;
						$events['message'] .= $lines[$i];
					}
					$events['message'] = htmlspecialchars(stripslashes($events['message']), ENT_QUOTES);
					break;
				}
			}
		}
		return $events;
	}
	
	function getMonthEvents($month, $year) {
		$events = array();
		$lines = file($this->datapath);
		$k = 0;
		$sorts = array();
		for ($i=0, $n=count($lines); $i<$n; $i++) {
			if (trim($lines[$i])=='<event>') {
				list($d, $m, $y) = explode('-', trim($lines[$i+2]));
				if (($m==$month || $m==0) && ($y==$year || $y==0)) {
					$sorts[$k] = trim($lines[$i+3]);
					list($h, $min) = explode(':', $sorts[$k]);
					$events[$k]['id'] = trim($lines[$i+1]);
					$events[$k]['day'] = $d;
					$events[$k]['month'] = $m;
					$events[$k]['year'] = $y;
					$events[$k]['hr'] = $h;
					$events[$k]['min'] = $min;
					$events[$k]['message'] = '';
					for ($i+=4;; $i++) {
						if (trim($lines[$i])=='</event>') break;
						$events[$k]['message'] .= $lines[$i];
					}
					$events[$k]['message'] = htmlspecialchars(stripslashes($events[$k]['message']), ENT_QUOTES);
					$k++;
				}
			}
		}
		array_multisort($sorts, SORT_ASC, SORT_NUMERIC, $events);
		return $events;
	}
		
	function displayMonth($dates) {
		$keys['LAST_MON'] = $dates['last']['mon'];
		$keys['LAST_YEAR'] = $dates['last']['year'];
		$keys['NEXT_MON'] = $dates['next']['mon'];
		$keys['NEXT_YEAR'] = $dates['next']['year'];
		$keys['MONTH'] = $dates['month'];
		$keys['YEAR'] = $dates['year'];
		$keys['MON'] = $dates['mon'];
		
		$events = $this->getMonthEvents($dates['mon'], $dates['year']);
		$dayevents = array();
		for ($count=0, $i=0, $n=count($events); $i<$n; $i++, $count++) {
			$d = $events[$i]['day'];
			$dayevents[$d][] = array (
				'id' => $events[$i]['id'], 
				'message' => nl2br($events[$i]['message']),
				'hr' => $events[$i]['hr']<10? $events[$i]['hr'] = '0' . $events[$i]['hr'] : $events[$i]['hr'],
				'min' => $events[$i]['min']<10? $events[$i]['min'] = '0' . $events[$i]['min'] : $events[$i]['min']
				);
		}
	
		$days = array();
		$filled = 0;
		$count = 0;
		for ($i=$dates['last']['days']-$dates['first']+1; $filled<$dates['first']; $i++, $filled++) {
			$days[$count]['DAY_' . $filled] = $i;
			$days[$count]['WHICH_' . $filled] = 'lastMonth';
			$days[$count]['EVENT_' . $filled] = '';
			$days[$count]['ID_' . $filled] = 'c' . $i . '-' . $dates['last']['mon'] . '-' . $dates['last']['year'];
		}
	
		$todays = $this->getDate();
		for ($i=1; $i<=$dates['days']; $i++, $filled++) {
			if ($filled==7) {
				$count++;
				$filled = 0;
			}
			$days[$count]['DAY_' . $filled] = $i;
			$days[$count]['WHICH_' . $filled] = '';
			$days[$count]['EVENT_' . $filled] = '';
			$days[$count]['ID_' . $filled] = 'd' . $i . '-' . $dates['mon'] . '-' . $dates['year'];
			if ($filled==0 || $filled==6) {
				$days[$count]['WHICH_' . $filled] .= ' weekend ';
			}
			if ($todays['mon']==$dates['mon'] && $todays['mday']==$i && $todays['year']==$dates['year']) {
				$days[$count]['WHICH_' . $filled] .= ' today ';
			}
			if (array_key_exists($i, $dayevents)) {
				$ids['DAY'] = $days[$count]['DAY_' . $filled];
				$ids['MONTH'] = $dates['mon'];
				$ids['YEAR'] = $dates['year'];
				$days[$count]['WHICH_' . $filled] .= ' event ';
				$days[$count]['EVENT_' . $filled] = $this->parseRecTemplate($this->parseTemplate($this->templates['event'], $ids), '<!-- BEGIN -->', '<!-- END -->', $dayevents[$i]);
			}
		}
		for ($i=1; $filled<7; $i++, $filled++) {
			$days[$count]['DAY_' . $filled] = $i;
			$days[$count]['WHICH_' . $filled] = 'nextMonth';
			$days[$count]['EVENT_' . $filled] = '';
			$days[$count]['ID_' . $filled] = 'c' . $i . '-' . $dates['next']['mon'] . '-' . $dates['next']['year'];
		}
		if ($this->sunday_endweek) $this->swap($days);
		return $this->parseRecTemplate($this->parseTemplate($this->templates['body'], $keys), '<!-- BEGIN -->', '<!-- END -->', $days);
	}
	
	function swap(&$days) {
		$n = count($days)-1;
		for ($i=0; $i<$n; $i++) {
			$days[$i]['WHICH_0'] = $days[$i+1]['WHICH_0'];
			$days[$i]['DAY_0'] = $days[$i+1]['DAY_0'];
			$days[$i]['EVENT_0'] = $days[$i+1]['EVENT_0'];
		}
		$days[$n]['WHICH_0'] = 'nextMonth';
		$days[$n]['DAY_0'] = $days[$n]['DAY_6']+1;
		$days[$n]['EVENT_0'] = '';
	}

	function getForm($do, $id, $day, $month, $year, $hr, $minute, $message, $add, $edit) {
		$max = $min = 5;
		$keys['DAY'] = '';
		$keys['MONTH'] = '';
		$keys['YEAR'] = '';
		$keys['HOUR'] = '';
		$keys['MINUTE'] = '';
		$keys['ID'] = $id;
		$keys['DO'] = $do;
		$keys['MESSAGE'] = $message;
		$keys['ADD'] = $add;
		$keys['EDIT'] = $edit;
	
		for ($i=1; $i<=31; $i++) {
			if ($i==$day) {
				$keys['DAY'] .= '<option value="' . $i . '" selected >' . $i . '</option>';
			} else {
				$keys['DAY'] .= '<option value="' . $i . '">' . $i . '</option>';
			}
		}
		for ($i=1; $i<=12; $i++) {
			if ($i==$month) {
				$keys['MONTH'] .= '<option value="' . $i . '" selected >' . $this->months[$i-1] . '</option>';
			} else {
				$keys['MONTH'] .= '<option value="' . $i . '">' . $this->months[$i-1] . '</option>';
			}
		}
		$tmp = $this->getDate();
		$year0 = $year>0? $year : $tmp['year'];
		for ($i=$year0-$min, $n=$year0+$max; $i<=$n; $i++) {
			if ($i==$year) {
				$keys['YEAR'] .= '<option value="' . $i . '" selected >' . $i . '</option>';
			} else {
				$keys['YEAR'] .= '<option value="' . $i . '">' . $i . '</option>';
			}
		}
		for ($i=0; $i<=23; $i++) {
			$j = $i<10? '0' . $i : $i;
			if ($i==$hr) {
				$keys['HOUR'] .= '<option value="' . $i . '" selected >' . $j . '</option>';
			} else {
				$keys['HOUR'] .= '<option value="' . $i . '">' . $j . '</option>';
			}
		}
		for ($i=0; $i<=59; $i++) {
			$j = $i<10? '0' . $i : $i;
			if ($i==$minute) {
				$keys['MINUTE'] .= '<option value="' . $i . '" selected >' . $j . '</option>';
			} else {
				$keys['MINUTE'] .= '<option value="' . $i . '">' . $j . '</option>';
			}
		}
		return $this->parseTemplate($this->templates['form'], $keys);
	}
	
	function addEvent($day, $month, $year, $hr, $min, $message, $input_id=null) {
		$id = $input_id==null? time() : $input_id;
		$handle = fopen($this->datapath, 'a') or exit('error1');
		if (get_magic_quotes_gpc()==0) {
			$message = addslashes($message);
		}
		$content = "\n<event>\n" . $id . "\n" . $day . '-' . $month . '-' . $year . "\n" . $hr . ':' . $min . "\n" . $message . "\n</event>";
		if (fwrite($handle, $content)===false) {
			fclose($handle);
			exit('error2');
		}
		fclose($handle);
	}
	
	function delEvent($id) {
		$content = '';
		$lines = file($this->datapath);
		for ($i=0, $n=count($lines); $i<$n; $i++) {
			if (trim($lines[$i])=='<event>') {
				if (trim($lines[$i+1])==$id) {
					for ($i++;; $i++) {
						if (trim($lines[$i])=='</event>') break;
					}
				} else {
					for (;; $i++) {
						$content .= $lines[$i];
						if (trim($lines[$i])=='</event>') break;
					}
				}
			}
		}
		$handle = fopen($this->datapath, 'w') or exit('error1');
		if (fwrite($handle, $content)===false) {
			fclose($handle);
			exit('error2');
		}
		fclose($handle);
	}
		
	function show_calendar($last=0, $next=0) {
		print '<div id="calendar">';
		$today = $this->getDate();
		for ($i=$last; $i>0; $i--) {
			$month = $today['mon']-$i;
			$year = $today['year'];
			if ($month<0) {
				$month = 12+$month;
				$year--;
			}
			if (checkdate($month, 1, $year)) {
				$this->show_month($month, $year);
			}
		}
		for ($i=0; $i<=$next; $i++) {
			$month = $today['mon']+$i;
			$year = $today['year'];
			if ($month>12) {
				$month = $month-12;
				$year++;
			}
			if (checkdate($month, 1, $year)) {
				$this->show_month($month, $year);
			}
		}
		print '</div>';
		print $this->parseTemplate($this->templates['js'], array('HTPATH'=>$this->htpath));
	}
	
	function show_month($month, $year) {
		$dates = $this->getMonthDetails($month, $year);
		print $this->displayMonth($dates);
	}
	
	function checkDocumentRoot() {
		return dirname($_SERVER['PHP_SELF'])==$this->htpath;
	}
	
	function parseTemplate($tpl, $keys) {
		$content = '';
		$vars = array_keys($keys);
		for ($i=0, $n=count($vars); $i<$n; $i++) {
			$vars[$i] = '{' . strtoupper($vars[$i]) . '}';
		}
		$content = str_replace($vars, $keys, $tpl);
		return $content;
	}

	function parseRecTemplate($tpl, $begin, $end, $keys) {
		$content = '';
		$begin_pos = strpos($tpl, $begin) + strlen($begin);
		$end_pos = strpos($tpl, $end);
		$length = $end_pos - $begin_pos;
		$subtpl = substr($tpl, $begin_pos, $length);
		$num_key = count($keys);
		$vars = $num_key>0? array_keys($keys[0]) : null;
		for ($i=0, $n=count($vars); $i<$n; $i++) {
			$vars[$i] = '{' . strtoupper($vars[$i]) . '}';
		}
		for ($i=0; $i<$num_key; $i++) {
			$content .= str_replace($vars, $keys[$i], $subtpl);
		}
		return substr_replace($tpl, $content, $begin_pos, $length);
	}
}

?>